/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.nanosn.coffeemaker.application.commands;

import com.nanosn.coffeemaker.Project;
import com.nanosn.coffeemaker.asm.ClassRenamer;
import com.nanosn.coffeemaker.freemarker.FMPP;
import com.nanosn.coffeemaker.project.ProjectSettings;
import com.nanosn.coffeemaker.project.ProjectSettingsFactory;
import com.nanosn.util.FileUtility;
import com.nanosn.util.Jar;
import com.nanosn.util.parsers.commandline.Command;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.catalina.startup.Bootstrap;
import org.ow2.util.asm.ClassAdapter;
import org.ow2.util.asm.ClassReader;
import org.ow2.util.asm.ClassVisitor;
import org.ow2.util.asm.ClassWriter;

/**
 * This Will run the tomcat server ..
 *      1- Copy the Catilina home files
 *          - these are the main files required by the Server to run
 *          - all these files are located in the resources server dir
 *
 *
 *      2- Copy compiled project files to the proper location --> ROOT/WEB-INF/classes/projectname/
 *          - we need to find a way to compile in place..
 *          - We might neet to tweek the package names using JarJar
 *             + ProjectDir:
 *             |-- Settings.class
 *             |-- Urls.class
 *             |-+ App1
 *               |-- Urls.class
 *               |-+ modles
 *               | |-- model1.class
 *               | |-- model2.class
 *               |-- Views.class
 *
 *      3- Copy template files to ROOT/
 *           - Follow the same app structure for the templates
 *
 *      4- Generate the web.xml file -- could be done along with step 1
 *      5- Generate the persistence.xml file -- will need so much work if allowing to change provider (toplink- hibernate)
 * 
 *
 *
 * @author selkhateeb
 */
//@Argument(RegularExpression = "runserver") //not required same as class name
@Deprecated
public class RunServerTomcat implements Command {

    public void run(String[] args) throws Exception {

        String catalina_home = Project.TMP + "webserver" + File.separator;

        generateServerFiles(catalina_home);

        copyCompiledClasses(catalina_home);

        runServer(catalina_home);
    }

    private void generateServerFiles(String catalina_home) throws Exception {
        String srcDir = Project.TEMPLATE_FILES_PACKAGE_DIRECTORY + File.separator
                        + "server";

        String tmpDirectory = Project.TMP + Project.TEMPLATE_FILES_PACKAGE_DIRECTORY
                              + File.separator + "server";

        //Extract the server files
        //Extract files to temp directory
        Jar.CopyFilesToLocation(Project.getApplicationJar(), srcDir, tmpDirectory);

        //Need ProjectName for web.xml
        ProjectSettings ps = ProjectSettingsFactory.getInstance();
        Map vars = new HashMap();
        vars.put("ProjectName", ps.getRootPackage());

        FMPP.RunFMPP(tmpDirectory, catalina_home, vars);
    }

    private void runServer(String catalina_home) {

        System.setProperty("catalina.home", catalina_home);

        Bootstrap.main(new String[]{});
    }

    public String getHelp() {
        return "Runs the embedded Tomcat Server";
    }

    private void copyCompiledClasses(String catalina_home) throws Exception {
        File pwd = new File(".");
        List<File> classFiles = getAllClassFilesInFolder(pwd);

        //now lets do some String replacements
        //Remove the last "/"
        String pwd_name = pwd.getAbsolutePath().substring(0, pwd.getAbsolutePath().lastIndexOf(File.separator));

        //Remover the project name
        String projectParentDirectory = pwd_name.substring(0, pwd_name.lastIndexOf(File.separator));
        System.out.println("projectParentDirectory = " + projectParentDirectory);


        String catalina_webapp_directory = catalina_home + File.separator + "webapps" + File.separator;

        String ROOT_WEBINF_classes_directory = catalina_webapp_directory
                                               + "ROOT" + File.separator
                                               + "WEB-INF" + File.separator
                                               + "classes" + File.separator;

        //Copy files to ROOT/WEB-INF/classes/projectname/
        for (File file : classFiles) {
            String destPath = file.getAbsolutePath().replace(projectParentDirectory, ROOT_WEBINF_classes_directory);
            //Create dirs if they dont exist
            File dest = new File(destPath);
            if (!dest.getParentFile().exists()) {
                dest.getParentFile().mkdirs();
            }

            //addPackageName(file, dest, ProjectSettingsFactory.getInstance().getRootPackage());

            FileUtility.Copy(file, dest);
        }
    }

    private void addPackageName(File original, File modifiedDest, String packageName) throws Exception {

        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            fis = new FileInputStream(original);
            fos = new FileOutputStream(modifiedDest);

            ClassWriter cw = new ClassWriter(0);
            ClassAdapter ca = new ClassRenamer(cw, packageName);//new PackageChanger(cw, packageName); // ca forwards all events to cw
            ClassReader cr = new ClassReader(fis);
            cr.accept(ca, 0);


            fos.write(cw.toByteArray());
        }
        finally {
            fos.flush();
            fos.close();
            fis.close();
        }

    }

    class PackageChanger extends ClassAdapter {

        String pkg;

        public PackageChanger(ClassVisitor cv, String pkg) {
            super(cv);
            this.pkg = pkg.replaceAll("\\.", "/");
            if (!this.pkg.endsWith("/")) {
                this.pkg += "/";
            }
        }

//        @Override
//        public void visitSource(String source, String debug) {
//            System.out.println("source = " + source);
//            System.out.println("debug = " + debug);
//        }
        @Override
        public void visit(int version, int access, String name,
                          String signature, String superName, String[] interfaces) {


//            System.out.println("class name = " + name);
//            System.out.println("class signature = " + signature);
//            //cv.visit(Opcodes.V1_5, access, name, signature, superName, interfaces);
            cv.visit(version, access, pkg + name, signature, superName, interfaces);
        }
//
//        @Override
//        public MethodVisitor visitMethod(int access, String name, String desc,
//                                         String signature, String[] exceptions) {
//            System.out.println("METHOD NAME = " + name);
//            System.out.println("METHOD desc = " + desc);
//            System.out.println("METHOD signature = " + signature);
//            return super.visitMethod(access, desc, desc, desc, exceptions);
//        }
    }

    private List<File> getAllClassFilesInFolder(File dir) {
        List<File> files = new ArrayList<File>();

        for (File file : dir.listFiles()) {
            if (file.isFile() && file.getAbsolutePath().endsWith(".class")) {
                files.add(file);
            }
            else if (file.isDirectory()) {
                files.addAll(getAllClassFilesInFolder(file));
            }
        }
        return files;
    }
}
